// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
//             1. General Purpose Register, 32bit * 15 = 480bit
// -------------------------------------------------------------------------------------------------

module k0a_core_gpr (
    input               core_clk       ,

    input               idu2gpr_we     ,
    input   [3:0]       idu2gpr_waddr  ,
    input   [31:0]      idu2gpr_wdata  ,

    input   [3:0]       idu2gpr_raddr1 ,
    output  [31:0]      gpr2idu_rdata1 ,

    input   [3:0]       idu2gpr_raddr2 ,
    output  [31:0]      gpr2idu_rdata2
);

reg  [31:0]  x1_ra;
reg  [31:0]  x2_sp;
reg  [31:0]  x3_gp;
reg  [31:0]  x4_tp;
reg  [31:0]  x5_t0;
reg  [31:0]  x6_t1;
reg  [31:0]  x7_t2;
reg  [31:0]  x8_s0;
reg  [31:0]  x9_s1;
reg  [31:0]  xa_a0;
reg  [31:0]  xb_a1;
reg  [31:0]  xc_a2;
reg  [31:0]  xd_a3;
reg  [31:0]  xe_a4;
reg  [31:0]  xf_a5;

wire x1_rd1 = (idu2gpr_raddr1 == 4'h1);
wire x2_rd1 = (idu2gpr_raddr1 == 4'h2);
wire x3_rd1 = (idu2gpr_raddr1 == 4'h3);
wire x4_rd1 = (idu2gpr_raddr1 == 4'h4);
wire x5_rd1 = (idu2gpr_raddr1 == 4'h5);
wire x6_rd1 = (idu2gpr_raddr1 == 4'h6);
wire x7_rd1 = (idu2gpr_raddr1 == 4'h7);
wire x8_rd1 = (idu2gpr_raddr1 == 4'h8);
wire x9_rd1 = (idu2gpr_raddr1 == 4'h9);
wire xa_rd1 = (idu2gpr_raddr1 == 4'ha);
wire xb_rd1 = (idu2gpr_raddr1 == 4'hb);
wire xc_rd1 = (idu2gpr_raddr1 == 4'hc);
wire xd_rd1 = (idu2gpr_raddr1 == 4'hd);
wire xe_rd1 = (idu2gpr_raddr1 == 4'he);
wire xf_rd1 = (idu2gpr_raddr1 == 4'hf);

wire x1_rd2 = (idu2gpr_raddr2 == 4'h1);
wire x2_rd2 = (idu2gpr_raddr2 == 4'h2);
wire x3_rd2 = (idu2gpr_raddr2 == 4'h3);
wire x4_rd2 = (idu2gpr_raddr2 == 4'h4);
wire x5_rd2 = (idu2gpr_raddr2 == 4'h5);
wire x6_rd2 = (idu2gpr_raddr2 == 4'h6);
wire x7_rd2 = (idu2gpr_raddr2 == 4'h7);
wire x8_rd2 = (idu2gpr_raddr2 == 4'h8);
wire x9_rd2 = (idu2gpr_raddr2 == 4'h9);
wire xa_rd2 = (idu2gpr_raddr2 == 4'ha);
wire xb_rd2 = (idu2gpr_raddr2 == 4'hb);
wire xc_rd2 = (idu2gpr_raddr2 == 4'hc);
wire xd_rd2 = (idu2gpr_raddr2 == 4'hd);
wire xe_rd2 = (idu2gpr_raddr2 == 4'he);
wire xf_rd2 = (idu2gpr_raddr2 == 4'hf);

wire x1_wr  = (idu2gpr_waddr == 4'h1) & idu2gpr_we;
wire x2_wr  = (idu2gpr_waddr == 4'h2) & idu2gpr_we;
wire x3_wr  = (idu2gpr_waddr == 4'h3) & idu2gpr_we;
wire x4_wr  = (idu2gpr_waddr == 4'h4) & idu2gpr_we;
wire x5_wr  = (idu2gpr_waddr == 4'h5) & idu2gpr_we;
wire x6_wr  = (idu2gpr_waddr == 4'h6) & idu2gpr_we;
wire x7_wr  = (idu2gpr_waddr == 4'h7) & idu2gpr_we;
wire x8_wr  = (idu2gpr_waddr == 4'h8) & idu2gpr_we;
wire x9_wr  = (idu2gpr_waddr == 4'h9) & idu2gpr_we;
wire xa_wr  = (idu2gpr_waddr == 4'ha) & idu2gpr_we;
wire xb_wr  = (idu2gpr_waddr == 4'hb) & idu2gpr_we;
wire xc_wr  = (idu2gpr_waddr == 4'hc) & idu2gpr_we;
wire xd_wr  = (idu2gpr_waddr == 4'hd) & idu2gpr_we;
wire xe_wr  = (idu2gpr_waddr == 4'he) & idu2gpr_we;
wire xf_wr  = (idu2gpr_waddr == 4'hf) & idu2gpr_we;

assign gpr2idu_rdata1 = ({32{x1_rd1}} & x1_ra) | ({32{x2_rd1}} & x2_sp) |
                        ({32{x3_rd1}} & x3_gp) | ({32{x4_rd1}} & x4_tp) |
                        ({32{x5_rd1}} & x5_t0) | ({32{x6_rd1}} & x6_t1) |
                        ({32{x7_rd1}} & x7_t2) | ({32{x8_rd1}} & x8_s0) |
                        ({32{x9_rd1}} & x9_s1) | ({32{xa_rd1}} & xa_a0) |
                        ({32{xb_rd1}} & xb_a1) | ({32{xc_rd1}} & xc_a2) |
                        ({32{xd_rd1}} & xd_a3) | ({32{xe_rd1}} & xe_a4) |
                        ({32{xf_rd1}} & xf_a5) ;

assign gpr2idu_rdata2 = ({32{x1_rd2}} & x1_ra) | ({32{x2_rd2}} & x2_sp) |
                        ({32{x3_rd2}} & x3_gp) | ({32{x4_rd2}} & x4_tp) |
                        ({32{x5_rd2}} & x5_t0) | ({32{x6_rd2}} & x6_t1) |
                        ({32{x7_rd2}} & x7_t2) | ({32{x8_rd2}} & x8_s0) |
                        ({32{x9_rd2}} & x9_s1) | ({32{xa_rd2}} & xa_a0) |
                        ({32{xb_rd2}} & xb_a1) | ({32{xc_rd2}} & xc_a2) |
                        ({32{xd_rd2}} & xd_a3) | ({32{xe_rd2}} & xe_a4) |
                        ({32{xf_rd2}} & xf_a5) ;

always @(posedge core_clk) if(x1_wr) x1_ra <= idu2gpr_wdata;
always @(posedge core_clk) if(x2_wr) x2_sp <= idu2gpr_wdata;
always @(posedge core_clk) if(x3_wr) x3_gp <= idu2gpr_wdata;
always @(posedge core_clk) if(x4_wr) x4_tp <= idu2gpr_wdata;
always @(posedge core_clk) if(x5_wr) x5_t0 <= idu2gpr_wdata;
always @(posedge core_clk) if(x6_wr) x6_t1 <= idu2gpr_wdata;
always @(posedge core_clk) if(x7_wr) x7_t2 <= idu2gpr_wdata;
always @(posedge core_clk) if(x8_wr) x8_s0 <= idu2gpr_wdata;
always @(posedge core_clk) if(x9_wr) x9_s1 <= idu2gpr_wdata;
always @(posedge core_clk) if(xa_wr) xa_a0 <= idu2gpr_wdata;
always @(posedge core_clk) if(xb_wr) xb_a1 <= idu2gpr_wdata;
always @(posedge core_clk) if(xc_wr) xc_a2 <= idu2gpr_wdata;
always @(posedge core_clk) if(xd_wr) xd_a3 <= idu2gpr_wdata;
always @(posedge core_clk) if(xe_wr) xe_a4 <= idu2gpr_wdata;
always @(posedge core_clk) if(xf_wr) xf_a5 <= idu2gpr_wdata;

endmodule
